<!doctype html>
<html>

    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
        <link rel="icon" href="./favicon.ico">
        <link rel="stylesheet" href="./css/reset.css" type="text/css" />
        <script src="./js/jquery-1.11.1.js" type="text/javascript"></script>
        <title>demo</title>
    </head>

    <body>
    <div class="paginator"></div>
    <script>
        (function($){
            // 1. 字符串模板对象
            var template = {
                    ellipsis: '<span class="pagination-ellipsis ellipsis">&hellip;</span>', // 省略号
                    prev: '<a class="item pagination-prev prev" href="javascript:void(0);">上一页</a>', // 上一页
                    next: '<a class="item pagination-next next" href="javascript:void(0);">下一页</a>', // 下一页
                    pageNumber:'<a class="item" href="javascript:void(0);"></a>' // 页码
                };

            // 2. 运行时数据
            var runData = {
                // 数据 - 总数据量
                total: 0,

                // 数据 - 总页码数
                totalPage: 0,
                
                // 数据 - 每页显示的数据量
                pageSize: 10,

                // 数据 - 当前页码
                currentPage: 1,

                // 数据 - 页码量(保持基数)
                pageCount: 7,
                
                // 数据 - 最小页码量
                minPageCount: 5,

                // 数据 - 最大页码量
                maxPageCount: 21,

                // 元素 - 省略符
                $ellipsis: [], // 分割元素集合，前省略符号和后省略符号在第一个元素和最后一个元素之间，只有

                // 状态 - 存在/不存在
                exist: {
                    // 省略符
                    ellipsis: false
                },

                // 状态 - 显隐
                visible: {
                    // 省略符
                    ellipsis: {
                        first: false,
                        last: false
                    }
                }
            };

            // 3. 辅助函数
            var handler = {
                // 初始化
                init: function(opts) {
                    // 参数修正 - 页码量
                    if (opts.pageCount < 5) {
                        opts.pageCount = opts.minPageCount;
                    }
                    if (opts.pageCount > opts.maxPageCount) {
                        opts.pageCount = opts.maxPageCount;
                    }

                    // 数据初始化 - totalPage
                    opts.totalPage = opts.total / opts.pageCount;
                }
            };
            
            // 4. 初始化函数 - opts 为深克隆后的数据
            function init(opts) {
                var self = $(this),
                    pageSize = opts.pageSize,
                    totalPage, // 总页码数
                    reminder, // 页数修正
                    str = '', // 拼接字符串
                    collection, // 分页的子元素合集
                    cItems, // 绑定响应事件的元素集合
                    $ellipsis, // 分隔元素集合
                    leftRange, // 显示分隔符的左区间
                    rightRange; // 显示分隔符的右区间;

                // 参数修正- pageCount 最小为 minPageCount 且为基数(不满基数的向上 +1)1
                if (opts.pageCount < opts.minPageCount) {
                    opts.pageCount = opts.minPageCount;
                }

                // 

                totalPage = parseInt(opts.total / opts.pageCount);
                reminder = opts.total % opts.pageSize;

                //页数修正
                if(reminder!=0){
                    totalPage++;
                }

                //修正pageCount,如果用户传入的不为偶数,如果直接使用影响到计算问题
                if(opts.pageCount%2==1){
                    opts.pageCount++;	
                }

                //判断是否显示分隔符(必须是要比显示页数打上2页以上才行)
                if(totalPage>=opts.pageCount+2){
                    opts.visibleEllipsis=true;
                }
            
                //页码上限调整(有可能用户存入了书签,但是访问的数据被删掉了,总页码数已经小于当时存储的当前页)
                if(opts.currentPage>totalPage){
                    opts.currentPage=totalPage;
                }
                //计算左分隔符区间就等于pageCount
                leftRange=opts.pageCount;
                rightRange=totalPage-(opts.pageCount/2);
                //判断右区间的一个偏移值
                rightDiff=opts.pageCount+opts.pageCount/2+1;
                //结构拼接-只有初始化的时候会调用
                str=spellPage(totalPage,opts.pageCount,opts.visibleEllipsis);
                self.html(str);
                cItems=self.find('.item');
                $ellipsis=self.find('.ellipsis');
                self.data('page',$.extend(
                    {},
                    opts,
                    {
                        totalPage:totalPage,
                        visibleEllipsis:opts.visibleEllipsis,
                        cItems:cItems,
                        $ellipsis:$ellipsis,
                        leftRange:leftRange,
                        rightRange:rightRange,
                        rightDiff:rightDiff,
                        prev:self.find('.prev'),
                        next:self.find('.next')
                    }));
                //页码填充
                fillPageNumber.call(this);
                //对应状态的管理
                pageStatus.call(this);
                //调用回调函数
                if(typeof opts.loadCallback == 'function'){
                    opts.loadCallback(opts.currentPage);
                }
            }
            
            //拼写页码字符串
            function spellPage(totalPage,pageCount,visibleEllipsis){
                /*
                    @note 
                        1. 判断当前页码是否在分隔符显示区间,没有分隔符的问题很简单
                        2. 拼接的时候是拼接的完整结构,不进行页码填充
                */
                var str='',
                    start=1,
                    end;
                //存在分隔符-带分第二个分隔符,带尾巴
                if(visibleEllipsis){
                    end=pageCount+1;
                    //以页码为准
                    for(;start<=end;start++){
                        //第一个分隔符
                        if(start==1){
                            str+=template.pageNumber+template.ellipsis;
                        }else if(start==end){
                            str+=template.ellipsis+template.pageNumber;
                        //常规拼接	
                        }else{
                            str+=template.pageNumber;
                        }	
                    }
                }else{
                    //以page为准
                    end=totalPage;
                    for(;start<=end;start++){
                        str+=template.pageNumber;
                    }
                }
                //返回字符串
                return template.prev+str+template.next;
            }
            
            //进行对应的角码值填充-和显示隐藏
            function fillPageNumber(){
                var data=$(this).data('page'),
                    //第一个页码(下表)
                    start=1,
                    //最后一个页码(下表)[不存在翻页的情况下,下表就是等于页码数]
                    end=data.totalPage,
                    //只有存在分隔符的分页类型才会用到一下三个变量
                    pStart=2,
                    pEnd,
                    //第二个页码的起始值
                    pageNumStart;
                //带分隔符(上下页+pageCount+3)
                if(data.visibleEllipsis){
                    //下一页前面的位置
                    end=pEnd=data.pageCount+1;
                    //如果当前页码在左闭区间
                    if(data.currentPage<data.leftRange){
                        pageNumStart=2;
                    //左区间以外
                    }else if(data.currentPage>=data.leftRange){
                        //起始页码计算方式固定不变
                        pageNumStart=data.currentPage-data.pageCount/2+1;
                        if(data.totalPage>=data.rightDiff){
                            //只有总页数大于了最小右侧偏移量时,才有意义考虑右区间
                            if(data.currentPage>=data.rightRange){
                                //修正的结束位置
                                pEnd=data.totalPage-pageNumStart+2;
                            }
                        }else{
                            pEnd=data.totalPage-pageNumStart+2;
                        }
                    }
                    data.cItems.each(function(currentPage,ele){
                        $this=$(this);
                        if(currentPage==start){
                            $this.text(currentPage);
                        //页码自增
                        }else if(currentPage>=pStart && currentPage<pEnd){
                            $this.text(pageNumStart);
                            pageNumStart++;
                            $this.show();
                        //剩下的隐藏
                        }else if(currentPage==pEnd){
                            $this.text(data.totalPage).show();	
                        }else if(currentPage>pEnd && currentPage<=end){
                            $this.hide();
                        }
                    });
                }else{
                    //没有翻页的页码填充,只会在初始化时执行一次(点击事件就屏蔽掉)
                    data.cItems.each(function(currentPage,ele){
                        if(currentPage>=start && currentPage<=end){
                            $(this).text(currentPage);
                        }
                    });
                }
            }
            
            //状态调整-预防相邻的尾页和前一页出现...分隔符
            function pageStatus(){
                /*
                    @对应状态的管理
                        1. 显示选中项目
                        2. 分隔符的显示和隐藏
                        3. 上一页和下一页的禁用(忘了考虑只有1页的情况)
                */
                var self=$(this),
                    data=self.data('page'),
                    //具体需要添加选中状态的那个元素的角码-在后面不停的进行修正(这个值是没有分隔符的情况下的正确值)
                    which=data.currentPage;
                //存在分隔符
                if(data.visibleEllipsis){
                    if(data.currentPage>=data.leftRange){
                        which=data.pageCount/2+1;
                    }
                }
                //1. 设置选中项
                data.cItems.removeClass('selected').eq(which).addClass('selected');
                //2. 设置上下页的状态
                //如果只有1页
                if(data.totalPage==1){
                    data.prev.addClass('disabled');
                    data.next.addClass('disabled');
                }else{
                    data.prev.removeClass('disabled');
                    data.next.removeClass('disabled');
                    if(data.currentPage==1){
                        data.prev.addClass('disabled');
                    }else if(data.currentPage==data.totalPage){
                        data.next.addClass('disabled');	
                    }
                }
                //3. 设置分隔符
                if(data.visibleEllipsis){
                    data.$ellipsis.show();
                    if(data.currentPage<data.leftRange){
                        data.$ellipsis.eq(0).hide();
                    }else if(data.currentPage>=data.rightRange){
                        data.$ellipsis.eq(1).hide();
                    }
                }
            }
            
            //点击事件
            function clickHanlder(target){
                /*
                    @直接调用 pageStatus 函数完成状态变更
                    @param 
                        1. target: 当前的点击元素
                */
                var data=$(this).data('page'),
                    $target=$(target);
                if($target.hasClass('item')){
                    //如果是点击的 -禁用的翻页键- 和 -当前键- 结束
                    if($target.hasClass('disabled') || $target.hasClass('selected')){
                        return;	
                    }
                    if($target.hasClass('prev')){
                        data.currentPage--;
                    }else if($target.hasClass('next')){
                        data.currentPage++;	
                    }else{
                        data.currentPage=$target.text();
                    }
                    //如果存在分隔符,页码重新填充
                    if(data.visibleEllipsis){
                        //页码重新填充
                        fillPageNumber.call(this);
                    }
                    //状态设置
                    pageStatus.call(this);
                    //调用回调函数
                    if(typeof data.clickPageCallback == 'function'){
                        data.clickPageCallback(data.currentPage);
                    }
                }
            }
            
            // 插件主体
            $.fn.paginator = function(opts) {
                // 配置数据合并
                var options = $.extend(
                    {},
                    runData,
                    $.fn.paginator.defaults,
                    opts
                );

                // jquery 的隐式迭代
                return this.each(function() {
                    init.call(this,options);
                        var self = $(this),
                            that = this,
                            data = self.data('page');

                        self.delegate('.item', 'click', function(event) {
                            clickHanlder.call(that,event.target);
                        });
                });
            };

            // 默认参数
            $.fn.paginator.defaults = {
                total: 0, // 数据 - 总数据量
                pageSize: 10, // 数据 - 每页显示的数据量
                currentPage: 1, // 数据 - 当前页码
                pageCount: 7, // 数据 - 页码量(保持基数)
                loadCallback: null, // 初始化完毕的回调函数 - 参数为页码数据
                changeCallback: null, // 点击页码的回调函数 - 参数为页码数据
            };
        })(jQuery);

        $('.paginator').paginator({
            clickPageCallback: function(e) {
                console.log('点击分页了', e);
            }
        });
    </script>
    </body>
</html>